package com.neu.flashmall.ms.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.neu.common.constant.RedisRegion;
import com.neu.flashmall.ms.entity.SysMenu;
import com.neu.flashmall.ms.entity.SysUser;
import com.neu.flashmall.ms.mapper.SysUserMapper;
import com.neu.flashmall.ms.service.SysMenuService;
import com.neu.flashmall.ms.service.SysUserService;
import com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil;
import com.neu.flashmall.ms.vo.UserVo;
import com.neu.flashmall.ms.vo.AuthorityVo;
import com.neu.flashmall.ms.vo.SysUserVo;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class SysUserServiceImpl implements SysUserService {
    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private SysMenuService sysMenuService;

    /**
     * 自动注入一个SysUserService是为了在本类中调用本类的方法的动态代理生效，例如@Cacheable的方法和@Transactional的方法
     */
    @Resource
    private SysUserService sysUserService;


    @Override
    public boolean checkUserName(String username) {
        SysUser sysUser = sysUserMapper.selectByUserName(username);
        if(sysUser == null){
            return true;
        }
        return false;
    }

    @Override
    public int register(SysUser user) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        user.setRole(2);
        user.setStatus(0);
        return sysUserMapper.insert(user);
    }

    @Override
    public boolean resetPassword(String username) {
        SysUser sysUser = sysUserMapper.selectByUserName(username);
        if(sysUser != null){
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            String encode = passwordEncoder.encode(username);
            sysUser.setPassword(encode);
            update(sysUser);
            return true;
        }
        return false;
    }

    @Override
    public boolean changePassword(SysUser sysUser) {
        if(sysUser != null){
            SysUser user = sysUserMapper.selectByUserName(sysUser.getUsername());
            String password = sysUser.getPassword();
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            String encode = passwordEncoder.encode(password);
            user.setPassword(encode);
            update(user);
            return true;
        }
        return false;
    }

    @Override
    public boolean checkPhone(UserVo userVo) {
        String phone = userVo.getPhone();
        SysUser sysUser = sysUserMapper.selectByPhone(phone);
        if(sysUser == null){
            return true;
        }else{
            if(sysUser.getId() == userVo.getId()){
                return true;
            }
        }
        return false;
    }

    @Override
    public SysUserVo login(String username, String password) {
        //返回ums中的id,在这里进行查询返回用户昵称
        SysUser sysUser = sysUserMapper.selectByUserName(username);
        if(sysUser == null){
            return null;
        }
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        boolean result = passwordEncoder.matches(password,sysUser.getPassword());
        if(result) {
            SysUserVo sysUserVo = new SysUserVo();
            sysUserVo.setUser(sysUser);
            String token = this.generateTokenForUser(sysUser.getId());
            sysUserVo.setToken(token);
            AuthorityVo authorityVo = this.toMakeUpAuthorityVo(sysUser.getRole());
            sysUserVo.setAuthorityVo(authorityVo);
            return sysUserVo;
        }
        return null;
    }

    @Override
    public String login(String username, String password, SysUserVo returnSysUserVo) {
        SysUserVo old = this.login(username,password);
        if(old == null){
            return "用户名或者密码错误";
        }
        SysUser sysUser = old.getUser();
        if(sysUser.getStatus() == 0){
            return "您账号已经关停，请咨询管理员";
        }
        returnSysUserVo.setUser(sysUser);
        returnSysUserVo.setToken(old.getToken());
        returnSysUserVo.setAuthorityVo(old.getAuthorityVo());
        return "success";
    }

    @Override
    public PageInfo<SysUser> getPaged(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        List<SysUser> list = sysUserMapper.selectAll();
        PageInfo<SysUser> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    @CacheEvict(value = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
            key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).generateSysUserIdKey(#id)")
    public int delete(long id) {
        return sysUserMapper.deleteByPrimaryKey(id);
    }

    @Override
    @CacheEvict(value = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
            key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).generateSysUserIdKey(#sysUser.id)")
    public int update(SysUser sysUser) {
        return sysUserMapper.updateByPrimaryKeySelective(sysUser);
    }



    @Override
    public String toMakeUpAuthorityVo(String username,String password,AuthorityVo result) {
        SysUserVo sysUserVo = this.login(username,password);
        if(sysUserVo == null) return "前端数据异常";
        SysUser sysUser = sysUserVo.getUser();
        if(sysUser == null) return "前端数据异常";
        result = this.toMakeUpAuthorityVo(sysUser.getRole());
        return "获取权限成功";
    }

    @Override
    public SysUserVo getUserWithAuthorityByToken(String token) {
        if(token == null || "".equals(token)) return null;

        SysUser sysUser = this.getSysUserByTokenWithRedis(token);
        if(sysUser == null) return null;
        AuthorityVo authorityVo = this.toMakeUpAuthorityVo(sysUser.getRole());
        SysUserVo sysUserVo = new SysUserVo();
        sysUserVo.setAuthorityVo(authorityVo);
        sysUserVo.setUser(sysUser);
        return sysUserVo;
    }

    @Override
    public String changeUserStatus(String username, Integer status) {
        if(status == 0){
            int result = this.sysUserMapper.updateStatusByUsername(username,1);
            if(result == 1) return "成功转换" + username + "用户状态为开启";
        }else{
            int result = this.sysUserMapper.updateStatusByUsername(username,0);
            if(result == 1) return "成功转换" + username + "用户状态为关停";
        }
        return "数据库异常";
    }

    /**
     * 将token保存到redis中：key：token value：sysUserId
     * 具体key：FlashMallManageSystem::token的具体值
     * @param token
     * @return
     */
    @Override
    public SysUser getSysUserByTokenWithRedis(String token) {
        if(StringUtils.isEmpty(token)) return null;
        Integer id = (Integer) this.redisTemplate.opsForValue().get(ManageSystemRedisKeyUtil.generateKey(token));
        if(id == null) return null;
        Long sysUserId = Long.valueOf(id);
        return this.sysUserService.getSysUserByIdWithRedis(sysUserId);
    }

    /**
     * 生成uuid的token，然后将token放到redis中，key是token，value是sysUserId
     * @param sysUserId
     * @return
     */
    @Override
    public String generateTokenForUser(Long sysUserId) {
        if(sysUserId == null) throw new NullPointerException();
        String token = UUID.randomUUID().toString();
        this.redisTemplate.opsForValue().set(ManageSystemRedisKeyUtil.generateKey(token),sysUserId,1, TimeUnit.DAYS);
        return token;
    }


    /**
     * 通过Redis存储SysUser,如果Redis中有就在Redis中获取，没有才去数据库寻找
     * key：flashMallManageSystem::sysUserId
     * @param sysUserId
     * @return
     */
    @Override
    @Cacheable(value = {RedisRegion.FLASH_MALL_MANAGE_SYSTEM_REGION},
            key = "T(com.neu.flashmall.ms.utils.ManageSystemRedisKeyUtil).generateSysUserIdKey(#sysUserId)")
    public SysUser getSysUserByIdWithRedis(Long sysUserId) {
        return this.sysUserMapper.selectByPrimaryKey(sysUserId);
    }

    @Override
    public String logout(String token) {
        this.redisTemplate.delete(ManageSystemRedisKeyUtil.generateKey(token));
        System.out.println(ManageSystemRedisKeyUtil.generateKey(token));
        return "退出登录成功";
    }


    private AuthorityVo toMakeUpAuthorityVo(Integer role) {
        Long roleId = Long.valueOf(String.valueOf(role));
        AuthorityVo result = new AuthorityVo();
        List<SysMenu> sysMenuList = this.sysMenuService.getAllSysMenuByRole(roleId);
        HashMap<String,Boolean> map = new HashMap<>();
        for(SysMenu sysMenu : sysMenuList){
            map.put(sysMenu.getProperty(),true);
        }
        result.setAuthorityMap(map);
        return result;
    }



}
